package viewer

import (
	"fmt"
	"gitee.com/alex_li/zangjingge/internal/db/rdb"
	"gitee.com/alex_li/zangjingge/internal/oss"
	"github.com/lishimeng/app-starter"
	"github.com/lishimeng/app-starter/persistence"
	"github.com/lishimeng/app-starter/server"
	"github.com/lishimeng/go-log"
	"io"
	"net/http"
	"os"
)

func readFile(ctx server.Context) {

	var err error

	fileId := ctx.C.Params().Get("fileId")
	token := getToken(ctx)

	docInfo, bucketInfo, err := getDocInfo(fileId)
	if err != nil {
		log.Info("get doc_info failed")
		log.Info(err)
		ctx.C.StatusCode(http.StatusNotFound)
		return
	}
	if !validToken(token, docInfo, bucketInfo) {
		log.Info("check token failed")
		log.Info(err)
		ctx.C.StatusCode(http.StatusForbidden)
		return
	}
	responseFile(ctx, docInfo, bucketInfo)
}

func responseFile(ctx server.Context, doc rdb.DocInfo, bucket rdb.BucketInfo) {

	fullPath := oss.GetAbsPath(bucket.RootPath, doc.FilePath)

	//设置文件名称
	ctx.C.Header("Content-Disposition", "attachment;filename="+doc.Name)
	ctx.C.ContentType("application/octet-stream;charset=utf8")
	ctx.C.Header("Content-Length", fmt.Sprintf("%d", doc.FileSize))

	_ = responseBytes(fullPath, ctx)
}

func responseBytes(filename string, ctx server.Context) error {
	// File
	file, err := os.Open(filename)
	if err != nil {
		return err
	}
	defer func() {
		_ = file.Close()
	}()
	tmp := make([]byte, 512)
	_, err = io.CopyBuffer(ctx.C.ResponseWriter(), file, tmp)

	if err != nil {
		return err
	}
	return nil
}

func getToken(ctx server.Context) string {
	token := ctx.C.GetHeader(TokenHeader)
	if len(token) == 0 {
		token = ctx.C.URLParam(TokenParam)
	}
	return token
}

func validToken(token string, docInfo rdb.DocInfo, bucketInfo rdb.BucketInfo) bool {
	auth := bucketInfo.Auth
	if auth == rdb.BucketPublic {
		return true
	}
	expectFile, ok := RamTokenContainer[token]
	if !ok {
		return false
	}
	if expectFile != docInfo.Code {
		return false
	}
	return true
}

func getDocInfo(fileId string) (doc rdb.DocInfo, bucket rdb.BucketInfo, err error) {
	err = app.GetOrm().Transaction(func(tx persistence.TxContext) (er error) {
		err = tx.Context.QueryTable(new(rdb.DocInfo)).
			Filter("code", fileId).One(&doc)
		if err != nil {
			return
		}
		err = tx.Context.QueryTable(new(rdb.BucketInfo)).
			Filter("code", doc.Bucket).One(&bucket)
		return
	})

	if err != nil {
		return
	}
	return
}
